package com.flow.framework.core.system.initialization;

import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import com.flow.framework.common.util.clazz.ClazzUtil;
import com.flow.framework.core.system.proxy.IProxy;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;

/**
 * 代理服务
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/1/23
 */
@Slf4j
public class ProxyService<T, S extends IProxy<T>> {

    /**
     * 被代理的class类型的名称
     */
    private String clazzTypeName;

    /**
     * 被代理的服务的类型和具体服务实现的map
     */
    private Map<T, S> cache;

    ProxyService(Type clazzType, Map<T, S> cache) {
        this.clazzTypeName = ClazzUtil.getShortByClazzName(clazzType.getTypeName());
        this.cache = cache;
    }

    /**
     * 获取具体的bean的Optional
     *
     * @param type 服务类型
     * @return bean的Optional
     */
    public Optional<S> typeOptional(T type) {
        if (null == type) {
            log.error("proxy bean type is null, proxied clazz type name: {}", clazzTypeName);
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        if (null == cache) {
            log.error("proxy beans is null, please check spring loading finish ? proxied proxied clazz type name: {}", clazzTypeName);
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Optional.ofNullable((S) cache.get(type));
    }

    /**
     * 获取具体的bean的Optional
     *
     * @param type 服务类型
     * @return bean
     */
    public S type(T type) {
        Optional<S> optional = typeOptional(type);
        if (!optional.isPresent()) {
            log.error("proxy bean type is null, proxied clazz type name: {}", clazzTypeName);
            throw new CheckedException(SystemErrorCode.OBJECT_NOT_FOUND_ERROR);
        }
        return optional.get();
    }

    @SuppressWarnings("unchecked")
    void setCache(Map<?, ? extends IProxy> cache) {
        this.cache = (Map<T, S>) cache;
    }
}